﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Channels;
using System.Text;
using System.Xml;
using LinFu.IoC.Configuration;
using LinFu.IoC.Interfaces;
using LinFu.IoC;

namespace CoreEx.Wcf.Common.Implementation.Compression
{
    [Implements(typeof(MessageEncodingBindingElement), ServiceName = "CustomMessageEncodingBindingElement")]
    public class CustomMessageEncodingBindingElement : MessageEncodingBindingElement, IInitialize
    {
        private IServiceContainer _serviceContainer;

        private MessageEncodingBindingElement _innerMessageEncodingBindingElement;

        public CustomMessageEncodingBindingElement(MessageEncodingBindingElement innerMessageEncodingBindingElement)
        {
            _innerMessageEncodingBindingElement = innerMessageEncodingBindingElement;
        }

        public override BindingElement Clone()
        {
            var bindingElement =
                _serviceContainer.GetService<MessageEncodingBindingElement>("CustomMessageEncodingBindingElement", _innerMessageEncodingBindingElement);
            return bindingElement;                
        }

        public override MessageEncoderFactory CreateMessageEncoderFactory()
        {
            var innerfactory = _innerMessageEncodingBindingElement.CreateMessageEncoderFactory();            
            var factory = _serviceContainer.GetService<MessageEncoderFactory>(innerfactory);
            return factory;
        }

        public override MessageVersion MessageVersion
        {
            get { return _innerMessageEncodingBindingElement.MessageVersion; }
            set { _innerMessageEncodingBindingElement.MessageVersion = value; }
        }

        /// <summary>
        /// Returns the typed object requested, if present, from the appropriate layer in the channel stack.
        /// </summary>
        /// <returns>
        /// The typed object <paramref name="T"/> requested if it is present or null if it is not.
        /// </returns>
        /// <param name="context">The <see cref="T:System.ServiceModel.Channels.BindingContext"/> for the current binding element.</param><typeparam name="T">The typed object for which the method is querying.</typeparam><exception cref="T:System.ArgumentNullException"><paramref name="context"/> is null.</exception>
        public override T GetProperty<T>(BindingContext context)
        {
            if (typeof(T) == typeof(XmlDictionaryReaderQuotas))
            {
                return _innerMessageEncodingBindingElement.GetProperty<T>(context);
            }
            
            return base.GetProperty<T>(context);
            

        }

        public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
        {
            context.BindingParameters.Add(this);
            return context.BuildInnerChannelFactory<TChannel>();
            //return base.BuildChannelFactory<TChannel>(context);
        }

        public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
        {
            context.BindingParameters.Add(this);
            return context.BuildInnerChannelListener<TChannel>();
        }


        public void Initialize(IServiceContainer source)
        {
            _serviceContainer = source;
        }
    }
}
